#ifndef PICKUP_H__
#define PICKUP_H__

class Pickup;

#include "PlayState.h"
#include "Constants.h"
#include "Player.h"
#include "FromString.h"
#include "MovableText.h"


#define DEFAULT_ACTIVE_TIME (10.0f)
#define TIME_PICKUP_AMOUNT (30.0f)
#define PICKUP_ANIM "pickup_spin"
#define SCORE_ANIM "score_spin"

class Pickup {
protected:
    PlayState *play_state;
    Ogre::SceneNode *node;
    OgreNewt::Body *body;
    Ogre::ParticleSystem *particles;
    
    
    Ogre::String collect_effect_name;
    Ogre::ParticleSystem *collect_effect;
    bool collect_effect_active;
    Ogre::Real collect_effect_time;
    bool hide_pickup;
        
    Ogre::ParticleSystem *addPickupParticles(Ogre::SceneNode *pNode, Ogre::String name, Ogre::String filename);
    Ogre::Entity *addPickupEntity(Ogre::SceneNode *pNode, Ogre::String name, Ogre::String filename);
    Ogre::BillboardSet *addBillBoard(Ogre::SceneNode *node, Ogre::String name, Ogre::String bb_name);
    OgreNewt::Body *addPickupBody(OgreNewt::World *world, Ogre::SceneNode *node, Ogre::Vector3 &size);
    
public:
    Pickup(Ogre::SceneNode *n, Ogre::String name, 
           Ogre::String bb_name, Ogre::String particle_name, Ogre::String col_ef_name,  
           OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params);
    virtual ~Pickup(void) {}
    
    OgreNewt::Body *getBody() { return body; }
    void setPlayState(PlayState *ps) { play_state = ps; }
    
    virtual void apply(Player *pl);
    virtual void animate(Ogre::Real time);
    virtual void reset();
    
} ;

class LifePickup : public Pickup {
public:
    LifePickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params) 
                        : Pickup(node, name, "LifePickup", "Pickup", "Pickup/CollectEffect", world, params) {}
    void apply(Player *pl);
} ;

class TimePickup : public Pickup {
private:
    Ogre::Real extra_time;


public:
    TimePickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params)
                        : Pickup(node, name, "TimePickup", "Pickup", "Pickup/CollectEffect", world, params) {
        std::map<Ogre::String, Ogre::String>::iterator it;
        it = params.find("extra_time");
        if (it != params.end())
            from_string<Ogre::Real>( extra_time, it->second.c_str(), std::dec);
        else
            extra_time = TIME_PICKUP_AMOUNT;
    }
    void apply(Player *pl);
} ;

class PowerUp : public Pickup {
public:
    bool respawn;
    Ogre::Real respawn_time;
    Ogre::Real active_time;
    
    PowerUp(Ogre::SceneNode *node, Ogre::String name, Ogre::String bb_name,
            OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params);
    virtual void undo(Player *pl) = 0;
} ;

class SizePickup : public PowerUp {
public:
    SizePickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params)
                : PowerUp(node, name, "SizePickup", world, params) {}
    void apply(Player *pl);
    void undo(Player *pl);
} ;

class InvertPickup : public PowerUp {
public:
    InvertPickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params)
                : PowerUp(node, name, "InvertPickup", world, params) {}
    void apply(Player *pl);
    void undo(Player *pl);
} ;

class SpeedPickup : public PowerUp {
public:
    SpeedPickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params)
                : PowerUp(node, name, "SpeedPickup", world, params) {}
    void apply(Player *pl);
    void undo(Player *pl);
} ;

class SensitivityPickup : public PowerUp {
public:
    SensitivityPickup(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params)
                : PowerUp(node, name, "SensitivityPickup", world, params) {}
    void apply(Player *pl);
    void undo(Player *pl);
} ;

class ScorePickup : public Pickup {
protected:
    int amount;
    bool animating;
    Ogre::MovableText *text;
    Ogre::SceneNode *text_node;
public:
    ScorePickup(Ogre::SceneNode *node, Ogre::String name, 
                Ogre::String particle_name, Ogre::String c_eff_name, 
                OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params, int a);
    void reset();
    void apply(Player *pl);
    void animate(Ogre::Real time);
} ;

class ScorePickup1 : public ScorePickup {
public:
    ScorePickup1(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params) 
        : ScorePickup(node, name, "Score1", "Score1/CollectEffect", world, params, 10) {
    }
    void apply(Player *pl);
} ;

class ScorePickup2 : public ScorePickup {
public:
    ScorePickup2(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params) 
        : ScorePickup(node, name, "Score2", "Score2/CollectEffect", world, params, 20) {
    }
    void apply(Player *pl);
} ;

class ScorePickup3 : public ScorePickup {
public:
    ScorePickup3(Ogre::SceneNode *node, Ogre::String name, OgreNewt::World *world, std::map<Ogre::String, Ogre::String> &params) 
        : ScorePickup(node, name, "Score3", "Score3/CollectEffect", world, params, 50) {
    }
    void apply(Player *pl);
} ;



#endif
